package com.marktim.beerbot;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Timer;
import java.util.TimerTask;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "beerbot")
public class BeerBot implements SerialPortEventListener {

	public final static int INTERVAL = 700;
	
	private static CommPortIdentifier portId1;
	private static OutputStream outputStream;
	private static SerialPort serialPort1;
	private static String TimeStamp;
	private boolean timerOn = false;
	private Timer timer;
	
	
	static boolean commandReceived = false;

	public enum ArmDirection {
		LEFT, CENTER, RIGHT
	}

	public enum ArmHeight {
		LOW, HIGH
	}

	@XmlElement(name = "busy")
	private boolean busy = false;

	@XmlElement(name = "left_movement")
	private int leftMovement;

	@XmlElement(name = "right_movement")
	private int rightMovement;

	@XmlElement(name = "arm_direction")
	private ArmDirection armDirection;

	@XmlElement(name = "arm_height")
	private ArmHeight armHeight;

	@XmlElement(name = "bottles_locked")
	private boolean lockedBottles = false;

	private static BeerBot instance;

	public static BeerBot getInstance() throws InterruptedException {
		if (instance == null) {
			instance = new BeerBot();
		}
		return instance;
	}

	private BeerBot() throws InterruptedException {
		armHeight = ArmHeight.LOW;
		armDirection = ArmDirection.CENTER;

		if (!timerOn) {
			timerOn = true;
			timer = new Timer();
			timer.schedule(getTask(), 1500);
		}

		try {
			portId1 = CommPortIdentifier.getPortIdentifier("COM8");
			TimeStamp = new java.util.Date().toString();
			serialPort1 = (SerialPort) portId1.open("ComControl", 2000);
			System.out.println(TimeStamp + ": " + portId1.getName()
					+ " opened for input");
			serialPort1.addEventListener(this);
			serialPort1.notifyOnDataAvailable(true);
			serialPort1.setSerialPortParams(
					2000000, // 1228800 //1843200,
					SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
					SerialPort.PARITY_NONE);
		} catch (Exception e) {
			System.err.println("SerialPort Error Application will end.");
			System.err.println("System.exit()");
			System.exit(0);
		}
	}
	
	public TimerTask getTask() {
		return new TimerTask() {
			public void run() {
				if (!commandReceived) {
					System.out.println("Servo's reset");
					setLeftMovement(90);
					setRightMovement(90);
				} else {
					timer.schedule(getTask(), INTERVAL);
				}
				commandReceived = false;
			}
		};
	}
	
	public void resetTimer() {
		timer.cancel();
		timer = new Timer();
		timer.schedule(getTask(), INTERVAL);
	}

	public void setLeftMovement(int amount) {
		if (!busy) {
			leftMovement = amount;
			String outputData = "" + (1000 + leftMovement);
			try {
				outputStream = serialPort1.getOutputStream();

				outputStream.write(outputData.getBytes());
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void setRightMovement(int amount) {
		if (!busy) {
			rightMovement = amount;
			String outputData = "" + (2180 - rightMovement);
			try {
				outputStream = serialPort1.getOutputStream();

				outputStream.write(outputData.getBytes());
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void serialEvent(SerialPortEvent arg0) {
	}

	public void setArmHeight(ArmHeight armHeight) {
		this.armHeight = armHeight;

		int height;
		if (!busy) {
			if (armHeight == ArmHeight.LOW) {
				height = 3000;
			} else {
				height = 3180;
			}
			String outputData = "" + height;
			try {
				outputStream = serialPort1.getOutputStream();
				outputStream.write(outputData.getBytes());
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void setArmDirection(ArmDirection armDirection) {
		this.armDirection = armDirection;

		int direction;
		if (!busy) {
			if (armDirection == ArmDirection.LEFT) {
				direction = 4000;
			} else if (armDirection == ArmDirection.RIGHT) {
				direction = 4180;
			} else {
				direction = 4090;
			}
			String outputData = "" + direction;
			try {
				outputStream = serialPort1.getOutputStream();
				outputStream.write(outputData.getBytes());
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void setCommandReceived(boolean b) {
		commandReceived = b;
	}

}
